//
//  ERClassAttributes.m
//  metadata
//
//  Created by easy on 11-5-30.
//  Copyright 2011 zeasy@qq.com. All rights reserved.
//

#import "ERClassAttributes.h"

#import <objc/objc-runtime.h>
#import "ERClass.h"
#import "ERField.h"
#import "ERMethod.h"
#import "ERProperty.h"
#import "ERSelector.h"

@implementation ERClassAttributes
@synthesize clazz;
@synthesize name;
@synthesize instanceSize;
@synthesize superClazz; 
@synthesize instanceFieldAliases; 
@synthesize instanceMethodAliases;
@synthesize iverLayout;
@synthesize weakIverLayout;
#pragma mark init
-(id) initWithERClass:(ERClass *) eClass{
	if (self = [super init]) {
		//clazz = [eClass retain];
		clazz = eClass;//弱引用
		instanceSize = class_getInstanceSize(clazz.source);
	}
	return self;
}

#pragma mark alias
-(void) mappingFieldAlias:(NSString *)alias withName:(NSString *) fieldName{
	if (!class_getInstanceVariable(self.clazz.source,ER_CSTRING(alias))) {	//不存在该key
		[self.instanceFieldAliases setObject:fieldName forKey:alias];
	}
}
-(void) mappingMethodAlias:(NSString *)alias withName:(NSString *) methodName{
	if (!class_getInstanceMethod(self.clazz.source, [ERSelector registerName:alias])) {
		[self.instanceMethodAliases setObject:methodName forKey:alias];
	}
}
-(void) mappingPropertyAlias:(NSString *)alias withName:(NSString *) propertyName{
	
	if (!class_getProperty(self.clazz.source, ER_CSTRING(alias))) {
		[self.propertyAliases setObject:propertyName forKey:alias]; 
	}
}

#pragma mark field
-(ERField *) instanceFieldWithName:(NSString *) fieldName{
	Ivar v = class_getInstanceVariable(self.clazz.source,ER_CSTRING(fieldName));
	if (!v) {
		NSString *fieldNameByAlias = [self.instanceFieldAliases valueForKey:fieldName];
		v = class_getInstanceVariable(self.clazz.source, ER_CSTRING(fieldNameByAlias));
	}
	return v?[[[ERField alloc] initWithIvar:v] autorelease]:nil;
}
 
-(NSArray *) allFields{ 
	unsigned int outCount;
	Ivar *vars = class_copyIvarList(self.clazz.source, &outCount);
	NSMutableArray *vs = [[NSMutableArray alloc] initWithCapacity:outCount];
	for (int i = 0; i < outCount; i++) {
		ERField *field = [[ERField alloc] initWithIvar:*(vars + i)];
		[vs addObject:field];
		[field release];
	}
	return [vs autorelease];
}
-(NSArray *) allFieldNames{ 
	NSArray *vars = [self allFields];
	NSMutableArray *names = [[NSMutableArray alloc] initWithCapacity:[vars count]];
	for (ERField *field in vars) {
		[names addObject:field.name];
	}
	return [names autorelease];
}
-(ERField *) classFieldWithName:(NSString *) fieldName{
	Ivar var = class_getClassVariable(self.clazz.source, ER_CSTRING(fieldName));
	return var ? [[[ERField alloc] initWithIvar:var] autorelease] : nil;
}
#pragma mark method
-(ERMethod *) instanceMethodWithName:(NSString *) methodName{
	Method m = class_getInstanceMethod(self.clazz.source, [ERSelector registerName:methodName]);
	if (!m) {
		NSString *methodNameByAlias = [self.instanceMethodAliases valueForKey:methodName];
		m = class_getInstanceMethod(self.clazz.source, [ERSelector registerName:methodNameByAlias]);
	}
	return m?[[[ERMethod alloc] initWithMethod:m] autorelease]:nil;
}
-(ERMethod *) classMethodWithName:(NSString *) methodName{
	Method m = class_getClassMethod(self.clazz.source, [ERSelector registerName:methodName]);
	return m ? [[[ERMethod alloc] initWithMethod:m] autorelease] : nil;
}
 
-(NSArray /*ERMethod*/*) allMethods{
	unsigned int outCount;
	Method *methods = class_copyMethodList(self.clazz.source, &outCount);
	NSMutableArray *ms = [[NSMutableArray alloc] initWithCapacity:outCount];
	for (int i = 0; i < outCount; i++) {
		ERMethod *method = [[ERMethod alloc] initWithMethod:*(methods + i)];
		[ms addObject:method];
		[method release];
	}
	return [ms autorelease];
}
-(NSArray /*NSString*/*) allMethodNames{
	NSArray *methods = [self allMethods];
	NSMutableArray *names = [[NSMutableArray alloc] initWithCapacity:[methods count]];
	for (ERMethod *method in methods) {
		[names addObject:method.name];
	}
	return [names autorelease];
}
#pragma mark property
-(ERProperty *) propertyWithName:(NSString *) propertyName{
	objc_property_t p = class_getProperty(self.clazz.source, ER_CSTRING(propertyName));
	if (!p) {
		NSString *propNameByAlias = [self.propertyAliases valueForKey:propertyName];
		p = class_getProperty(self.clazz.source, ER_CSTRING(propNameByAlias));
	}
	return p?[[[ERProperty alloc] initWithProperty:p atERClass:self.clazz] autorelease]:nil;
}
 
-(NSArray /*ERProperty*/*) allProperties{
	unsigned int outCount;
	objc_property_t * props = class_copyPropertyList(self.clazz.source, &outCount);
	NSMutableArray *properties = [[NSMutableArray alloc] initWithCapacity:outCount];
	for (int i = 0; i < outCount; i++) {
		ERProperty *prop = [[ERProperty alloc] initWithProperty:*(props + i) atERClass:self.clazz];
		[properties addObject:prop];
		[prop release];
	}
	return [properties autorelease];
}
-(NSArray /*NSString*/*) allPropertyNames{
	NSArray *props = [self allProperties];
	NSMutableArray *names = [[NSMutableArray alloc] initWithCapacity:[props count]];
	for (ERProperty *prop in props) {
		[names addObject:prop.name];
	}
	return [names autorelease];
}
#pragma mark property setter/getter
-(NSString *) name{
	return [ER_STRING_ALLOC(class_getName(self.clazz.source)) autorelease]; 
}
 
-(ERClass *) superClazz{
	return [[[ERClass alloc] initWith:class_getSuperclass(self.clazz.source)] autorelease];
}
-(void) setSuperClazz:(ERClass *) erClazz{
	class_setSuperclass(self.clazz.source, erClazz.source);
}
-(int) version{
	return class_getVersion(self.clazz.source);
}
-(void) setVersion:(int) ver{
	class_setVersion(self.clazz.source, ver);
}
-(NSString *) iverLayout{
	return [ER_STRING_ALLOC(class_getIvarLayout(self.clazz.source)) autorelease];
}
-(void) setIverLayout:(NSString *) layout{
	class_setIvarLayout(self.clazz.source, ER_CSTRING(layout));
}
-(NSString *) weakIverLayout{
	return [ER_STRING_ALLOC(class_getWeakIvarLayout(self.clazz.source)) autorelease];
}
-(void) setWeakIvarLayout:(NSString *) layout{
	class_setWeakIvarLayout(self.clazz.source, ER_CSTRING(layout));
}
 
-(NSMutableDictionary *) instanceFieldAliases{
	if (!instanceFieldAliases) {
		NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
		instanceFieldAliases = [dict retain];
		[dict release];
	}
	return instanceFieldAliases;
} 

-(NSMutableDictionary *) instanceMethodAliases{
	if (!instanceMethodAliases) {
		NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
		instanceMethodAliases = [dict retain];
		[dict release];
	}
	return instanceMethodAliases;
}


-(NSMutableDictionary *) propertyAliases{
	if (!propertyAliases) {
		NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
		propertyAliases = [dict retain];
		[dict release]; 
	}
	return propertyAliases;
}
-(void) dealloc{
	//[clazz release]; 弱引用
	[name release];
	
	[instanceFieldAliases release];
	[instanceMethodAliases release];
	[propertyAliases release];
	[super dealloc];
}
@end
